1 module unde.games.renderer; 2 3 import std.format; 4 import std.conv; 5 import std.math; 6 import std.string; 7 import std.stdio; 8 9 import derelict.sdl2.image; 10 import derelict.sdl2.sdl; 11 import derelict.opengl3.gl3; 12 import derelict.opengl3.gl; 13 import std.algorithm.comparison; 14 15 import std.utf; 16 import unde.global_state; 17 import unde.games.obj_loader; 18 19 private GLuint[string] textures; 20 21 /* ---------------------------------------------------------------------------- */ 22 bool apply_material(GlobalState gs, shared MtlMaterial *mtl, 23 string delegate(GlobalState gs, string name) tex_anim = null) 24 { 25 float[4] c; 26 27 GLenum fill_mode; 28 int ret1, ret2; 29 float opacity = 1.0; 30 31 if (mtl.transparency) opacity = mtl.transparency; 32 33 if (mtl.diffuse[0].isNaN()) 34 c = [0.8f, 0.8f, 0.8f, opacity]; 35 else 36 c = mtl.diffuse ~ opacity; 37 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, cast(const(float)*)c); 38 39 //if (mtl.specular[0].isNaN()) 40 c = [0.0f, 0.0f, 0.0f, 1.0f]; 41 //else 42 // c = mtl.specular ~ 1.0f; 43 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, cast(const(float)*)c); 44 45 if (mtl.ambient[0].isNaN()) 46 c = [0.2f, 0.2f, 0.2f, 1.0f]; 47 else 48 c = mtl.ambient ~ 1.0f; 49 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT, cast(const(float)*)c); 50 51 if (mtl.emissive[0].isNaN()) 52 c = [0.0f, 0.0f, 0.0f, 1.0f]; 53 else 54 c = mtl.emissive ~ 1.0f; 55 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, cast(const(float)*)c); 56 57 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 0.0f); 58 59 glPolygonMode(GL_FRONT_AND_BACK, false ? GL_LINE : GL_FILL); 60 61 //Not Two sided 62 glEnable(GL_CULL_FACE); 63 64 bool normals = false; 65 if(mtl.map_diffuse !is null) 66 { 67 string tex_name = mtl.map_diffuse; 68 if (tex_anim) tex_name = tex_anim(gs, tex_name); 69 string p = format("models/%s", tex_name); 70 71 GLuint texture_name; 72 bool link; 73 if (p !in textures) 74 { 75 glGenTextures(1, &texture_name);// generate GL-textures ID's 76 link = true; 77 } 78 else texture_name = textures[p]; 79 //writefln("texture_name=%s", texture_name); 80 glBindTexture(GL_TEXTURE_2D, texture_name);// Binding of texture name 81 82 if (link) 83 { 84 // 85 //redefine standard texture values 86 // 87 // We will use linear interpolation for magnification filter 88 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 89 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 90 // tiling mode 91 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, true ? GL_REPEAT : GL_CLAMP); 92 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, true ? GL_REPEAT : GL_CLAMP); 93 94 auto image = IMG_Load(p.toStringz); 95 if (!image) 96 { 97 throw new Exception(format("Error while loading texture: %s", p)); 98 } 99 100 // Texture specification 101 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 102 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, image.w, image.h, 0, GL_RGBA, GL_UNSIGNED_BYTE, 103 image.pixels); 104 SDL_FreeSurface(image); 105 106 textures[p] = texture_name; 107 } 108 return true; 109 } 110 else 111 { 112 glBindTexture(GL_TEXTURE_2D, 0); 113 } 114 115 return false; 116 } 117 118 GLuint[shared ObjMesh*] gl_lists; 119 120 import core.runtime; 121 Throwable.TraceInfo getStackTrace() { 122 123 version(Posix) { 124 // druntime cuts out the first few functions on the trace as they are internal 125 // so we'll make some dummy functions here so our actual info doesn't get cut 126 Throwable.TraceInfo f5() { return defaultTraceHandler(); } 127 Throwable.TraceInfo f4() { return f5(); } 128 Throwable.TraceInfo f3() { return f4(); } 129 Throwable.TraceInfo f2() { return f3(); } 130 auto stuff = f2(); 131 } else { 132 auto stuff = defaultTraceHandler(); 133 } 134 135 return stuff; 136 } 137 138 139 /* ---------------------------------------------------------------------------- */ 140 void recursive_render (GlobalState gs, shared ObjFile *sc, 141 bool delegate(GlobalState gs, string name) anim = null, 142 string delegate(GlobalState gs, string name) tex_anim = null, 143 bool dontcache = false, bool reverse = false) 144 { 145 //writefln("%s", getStackTrace()); 146 147 foreach(i; 0..sc.objects.length) 148 { 149 shared ObjObject *object; 150 if (!reverse) object = sc.objects[i]; 151 else object = sc.objects[sc.objects.length-1-i]; 152 153 GLuint prev_tex_id_idx = 0; 154 155 glPushMatrix(); 156 157 bool draw = true; 158 string name = object.name; 159 if (anim) draw = anim(gs, name); 160 161 if (draw) 162 { 163 /* draw all meshes assigned to this node */ 164 foreach (mesh; object.meshes) { 165 //writefln("mesh %d. material %d", n, mesh.mMaterialIndex); 166 bool is_texture = apply_material(gs, sc.mtl.materials[mesh.material], tex_anim); 167 168 if(object.normals is null) { 169 glDisable(GL_LIGHTING); 170 } else { 171 glEnable(GL_LIGHTING); 172 } 173 174 glDisable(GL_COLOR_MATERIAL); 175 176 bool full_draw; 177 if (!tex_anim && !dontcache) 178 { 179 if (mesh in gl_lists) 180 { 181 glCallList(gl_lists[mesh]); 182 } 183 else 184 { 185 gl_lists[mesh] = glGenLists(1); 186 if (gl_lists[mesh] <= 0) 187 throw new Exception(format("Error while glGenLists: %s", gl_lists[mesh])); 188 glNewList(gl_lists[mesh], GL_COMPILE_AND_EXECUTE); 189 full_draw = true; 190 } 191 } 192 else full_draw = true; 193 194 if (full_draw) 195 { 196 foreach (face; mesh.faces) { 197 GLenum face_mode; 198 199 switch(face.length) { 200 case 1: face_mode = GL_POINTS; break; 201 case 2: face_mode = GL_LINES; break; 202 case 3: face_mode = GL_TRIANGLES; break; 203 default: face_mode = GL_POLYGON; break; 204 } 205 206 glBegin(face_mode); 207 208 foreach(index; face) { 209 //glColor4fv(0.0f,0.0f,0.0f,1.0f); 210 211 if (is_texture && index.tex >= 0) 212 glTexCoord2f(object.texcoords[index.tex][0], 1.0-object.texcoords[index.tex][1]); 213 214 if(index.normal >= 0) 215 { 216 float[3] normal = [ object.normals[index.normal][0], 217 -object.normals[index.normal][1], 218 -object.normals[index.normal][2]]; 219 glNormal3fv(normal.ptr); 220 } 221 222 if (index.vert >= 0) 223 { 224 float[3] coords = [-object.vertices[index.vert][0], 225 object.vertices[index.vert][1], 226 object.vertices[index.vert][2]]; 227 glVertex3fv(coords.ptr); 228 } 229 } 230 231 glEnd(); 232 } 233 } 234 235 if (!tex_anim && !dontcache && full_draw) 236 { 237 glEndList(); 238 } 239 } 240 } 241 242 glPopMatrix(); 243 } 244 } 245 246 void render_box (float[6] box) 247 { 248 glBegin(GL_POLYGON); 249 glVertex3f(box[0], box[1], box[2]); 250 glVertex3f(box[0], box[4], box[2]); 251 glVertex3f(box[3], box[4], box[2]); 252 glVertex3f(box[3], box[1], box[2]); 253 glEnd(); 254 255 glBegin(GL_POLYGON); 256 glVertex3f(box[0], box[1], box[5]); 257 glVertex3f(box[0], box[4], box[5]); 258 glVertex3f(box[3], box[4], box[5]); 259 glVertex3f(box[3], box[1], box[5]); 260 glEnd(); 261 262 glBegin(GL_POLYGON); 263 glVertex3f(box[0], box[1], box[2]); 264 glVertex3f(box[0], box[4], box[2]); 265 glVertex3f(box[0], box[4], box[5]); 266 glVertex3f(box[0], box[1], box[5]); 267 glEnd(); 268 269 glBegin(GL_POLYGON); 270 glVertex3f(box[3], box[1], box[2]); 271 glVertex3f(box[3], box[4], box[2]); 272 glVertex3f(box[3], box[4], box[5]); 273 glVertex3f(box[3], box[1], box[5]); 274 glEnd(); 275 276 glBegin(GL_POLYGON); 277 glVertex3f(box[0], box[1], box[2]); 278 glVertex3f(box[3], box[1], box[2]); 279 glVertex3f(box[3], box[1], box[5]); 280 glVertex3f(box[0], box[1], box[5]); 281 glEnd(); 282 283 glBegin(GL_POLYGON); 284 glVertex3f(box[0], box[4], box[2]); 285 glVertex3f(box[3], box[4], box[2]); 286 glVertex3f(box[3], box[4], box[5]); 287 glVertex3f(box[0], box[4], box[5]); 288 glEnd(); 289 } 290 291 GLuint load_texture(string path, bool grayscale = false, int skiplines=0) 292 { 293 GLuint texture_name; 294 glGenTextures(1, &texture_name);// generate GL-textures ID's 295 glBindTexture(GL_TEXTURE_2D, texture_name);// Binding of texture name 296 297 // 298 //redefine standard texture values 299 // 300 // We will use linear interpolation for magnification filter 301 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 302 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 303 // tiling mode 304 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, true ? GL_REPEAT : GL_CLAMP); 305 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, true ? GL_REPEAT : GL_CLAMP); 306 307 auto image = IMG_Load(path.toStringz()); 308 if (!image) 309 { 310 throw new Exception(format("Error while loading texture: %s", path)); 311 } 312 313 // Texture specification 314 glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); 315 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, 316 image.w, image.h-skiplines, 0, grayscale?GL_LUMINANCE:GL_RGBA, GL_UNSIGNED_BYTE, 317 image.pixels + skiplines*image.w); 318 319 return texture_name; 320 } 321 322 void print_text(string text) 323 { 324 string[] encoding = ["@"," ","!",`"`,"#","$","%","&","'","(",")","*","+",",","-",".", 325 "/","0","1","2","3","4","5","6","7","8","9",":",";","<","=",">", 326 "?","@","A","B","C","D","E","F","G","H","I","J","K","L","M","N", 327 "O","P","Q","R","S","T","U","V","W","X","Y","Z","[",`\`,"]","^", 328 "_","`","a","b","c","d","e","f","g","h","i","j","k","l","m","n", 329 "o","p","q","r","s","t","u","v","w","x","y","z","{","|","}","~", 330 " "," "," ","Ё"," "," "," "," "," "," "," "," "," "," "," "," ", 331 " "," "," ","ё"," "," "," "," "," "," "," "," "," "," "," "," ", 332 "ю","а","б","ц","д","е","ф","г","х","и","й","к","л","м","н","о", 333 "п","я","р","с","т","у","ж","в","ь","ы","з","ш","э","щ","ч","ъ", 334 "Ю","А","Б","Ц","Д","Е","Ф","Г","Х","И","Й","К","Л","М","Н","О", 335 "П","Я","Р","С","Т","У","Ж","В","Ь","Ы","З","Ш","Э","Щ","Ч","Ъ"]; 336 337 size_t x = 0; 338 int y = 0; 339 for (size_t i=0; i < text.length; i+=text.stride(i)) 340 { 341 string chr = text[i..i+text.stride(i)]; 342 343 if (chr == "\n") 344 { 345 y--; 346 x=0; 347 continue; 348 } 349 350 size_t code = -1; 351 foreach(j, enc; encoding) 352 { 353 if (chr == enc) 354 { 355 code = j; 356 break; 357 } 358 } 359 360 assert(code != -1, chr); 361 float cx = (code%16)/16.0; 362 float cy = (code/16)/12.0; 363 364 glBegin(GL_POLYGON); 365 glTexCoord2f(cx, cy); 366 glVertex3f(x, y, -10.0); 367 glTexCoord2f(cx, cy+1.0/12); 368 glVertex3f(x, y-1.0, -10.0); 369 glTexCoord2f(cx+1.0/16, cy+1.0/12); 370 glVertex3f(x+1.0, y-1.0, -10.0); 371 glTexCoord2f(cx+1.0/16, cy); 372 glVertex3f(x+1.0, y, -10.0); 373 glEnd(); 374 375 x++; 376 } 377 } 378 379